(*Treatment of image*)

(** Dimensions of an image **)
let get_dims img =
  ((Sdlvideo.surface_info img).Sdlvideo.w,
   (Sdlvideo.surface_info img).Sdlvideo.h)

(** Load an image **)
let load_image file_name =
  Sdlloader.load_image file_name

(** Save an image **)
let save_to_bmp img name =
  Sdlvideo.save_BMP img name

(** Get pixel (x, y) color of an image **)
let get_pixel img x y =
  Sdlvideo.get_pixel_color img x y

(** Set pixel (x, y) color of an image **)
let set_pixel img x y color =
  Sdlvideo.put_pixel_color img x y color

(** Load a GMisc.Image from a file name **)
let get_GImage img img_name =
  save_to_bmp img img_name;
  GMisc.image ~file:img_name

(** Detection of outlines 
    Draw the outlines in Black (0, 0, 0) on the image **)
let detect_outlines img_name =
  let img = load_image img_name in
  let (w, h) = get_dims img in
    for i = 0 to w - 1 do
      for j = 0 to h - 1 do
        if (i + 1) < w then
	  (*Comparison between current pixel and right pixel*)
          let (r1, g1, b1) = get_pixel img i j in
          let (r2, g2, b2) = get_pixel img (i + 1) j in
            if ((r1, g1, b1) <> (r2, g2, b2)) then
	      set_pixel img i j (0, 0, 0);
        if (j + 1) < h then
	  (*Comparison between current pixel and bottom pixel*)
          let (r1, g1, b1) = get_pixel img i j in
          let (r2, g2, b2) = get_pixel img i (j + 1) in
	    if ((r1, g1, b1) <> (r2, g2, b2)) then
              set_pixel img i j (0, 0, 0);
      done
    done;
    let output_img_name = (img_name ^ "_O") in
      save_to_bmp img output_img_name

(*Areas count*)

(** Returns if color is present in the list of colors formed by
    triplets of the form (r, g, b) **)
let rec color_exists (r, g, b) = function
    [] -> false
  | (r1, g1, b1)::t when (r, g, b) <> (r1, g1, b1)
			      -> color_exists (r, g, b) t
  | _  -> true

(** Get the list of the differents colors presents in the map
    the list is formed by triplets of the form (r, g, b) **)
let get_color_areas img_name =
  let img = load_image img_name in
  let l = ref [] in
  let (w, h) = get_dims img in
    for i = 0 to w - 1 do
      for j = 0 to h - 1 do
        let (r, g, b) = get_pixel img i j in
	  if ((j > 0) &&
		((get_pixel img i j) <> (get_pixel img i (j - 1))))
	      || ((i > 0) &&
		((get_pixel img i j) <> (get_pixel img (i- 1) j))) then
              if (not (color_exists (r, g, b) !l)) then
		l := (r, g, b)::!l;
      done
    done;
    !l

(** Writes a string in a file **)
let wr_str file_name str =
  let out_channel = open_out file_name in
    output_string out_channel str;
    close_out out_channel

(** Compares 2 colors associated to their altitude **)
let compare_altCol (r1, g1, b1, a1) (r2, g2, b3, a2) =
  if (a1 < a2) then -1
  else if (a1 > a2) then 1
  else 0

(** Generates a string of 3 char from an int n 
    with 0 <= n <= 255 **)
let int_to_3NumInt n =
  let s = string_of_int n in
    if (String.length s = 1) then ("00" ^ s)
    else if (String.length s = 2) then ("0" ^ s)
	     else s

(** Writes output file of the differents altitudes
    l is a quadruplet of the form : (r, g, b, altitude) **)
let write_str_color_areas l =
  let sl = List.sort compare_altCol l in
  let number_color_str = "Number of color areas : " ^ string_of_int
    (List.length  sl)
  in  
  let rec build_string_areas str = function
      [] -> str
    | (r, g, b, a)::t ->
	"\n(" ^ (int_to_3NumInt  r) ^
	  ", " ^ (int_to_3NumInt  g) ^
	  ", " ^ (int_to_3NumInt b) ^
	  ")" ^ " | " ^ (int_to_3NumInt a) ^
          build_string_areas str t
  in
  let colors_str = (build_string_areas "" sl) in
  let final_str = number_color_str ^ colors_str in
    wr_str "color_areas.txt" final_str

(** Reads the file with the differents altitudes **)
let read_str_color_areas () =
  let l = ref [] in
  let in_channel = open_in "color_areas.txt" in
  let line1 = input_line in_channel in
  let nb_colors =
    int_of_string (String.sub line1 24 ((String.length line1) - 24))
  in
    for i = 0 to nb_colors - 1 do
      let curLine = input_line in_channel in
      let q = (int_of_string (String.sub curLine 1 3),
	       int_of_string (String.sub curLine 6 3),
               int_of_string (String.sub curLine 11 3),
               int_of_string (String.sub curLine 18 ((String.length
							curLine) -
						       18)))
      in
        l := q::!l
    done;
    List.rev !l

(** Get the altitude of the given color from a (r, g, b, alt)list **)
let get_altitude c l =
  let (r, g, b) = c in
  let rec f = function
      [] -> 0
    | (r2, g2, b2, a)::h when (r, g, b) = (r2, g2, b2) -> a
    | h::t -> f t
  in
    f l

(** Get the altitude of the given color from a file generated from
    write_str_color_areas **)
let get_altitude_from_file c =
  let l = read_str_color_areas () in
    get_altitude c l

(** Get the matrix of (bool, alt) that represents the outlines of the image
    l is the list of colors presents in the image **)
let get_outlines_mat img_name l =
  let img = load_image img_name in
  let (w, h) = get_dims img in
  let mat = Array.make_matrix h w (false, 0) in
    for i = 0 to w - 1 do
      for j = 0 to h - 1 do
 	if (i + 1) < w then
          (*Comparison between current pixel and right pixel*)
          let (r1, g1, b1) = get_pixel img i j in
          let (r2, g2, b2) = get_pixel img (i + 1) j in
            if ((r1, g1, b1) <> (r2, g2, b2)) then
 	      mat.(j).(i) <- (true, get_altitude (r1, g1, b1) l);
	if (j + 1) < h then
          (*Comparison between current pixel and bottom pixel*)
          let (r1, g1, b1) = get_pixel img i j in
          let (r2, g2, b2) = get_pixel img i (j + 1) in
	    if ((r1, g1, b1) <> (r2, g2, b2)) then
	      mat.(j).(i) <- (true, get_altitude (r1, g1, b1) l);
      done
    done;
    mat

(** Draws the grid in black with vertical and horizontal offset **)
let get_grid_mat img_name pasX pasY l =
  begin
    let img = load_image img_name in
    let h = snd (get_dims img) in
    let w = fst (get_dims img) in
    let mat = Array.make_matrix h w (false, 0) in
    let j = ref 0 in
      while !j < h do
	for i = 0 to w - 1 do
          mat.(i).(!j) <- (true, get_altitude (get_pixel img i !j) l)
	done;
	j := !j + pasY;
      done;
      let i = ref 0 in
	while !i < w do
          for j = 1 to h - 1 do
            mat.(!i).(j) <- (true, get_altitude (get_pixel img !i j) l)
          done;
          i := !i + pasX;
	done;
	mat
  end	    

(** Return the resultant matrix. Both matrixes have to have same
    dimensions **)
let bunk_mat mat1 mat2 =
  let w = Array.length mat1.(0) in
  let h = Array.length mat1 in
  let mat = Array.make_matrix w h (false, 0) in
    for i = 0 to h do
      for j = 0 to w do
	let (b1, a1) = mat1.(i).(j) in
	let (b2, a2) = mat2.(i).(j) in
 	  mat.(i).(j) <- (b1 && b2, a1)
      done
    done;
  mat
    
(** Draws the grid in black with vertical and horizontal pitch **)
let draw_grid img_name pasX pasY =
  begin
    let img = load_image img_name in
    let h = snd (get_dims img) in
    let w = fst (get_dims img) in
    let j = ref 0 in
      while !j < h do
	for i = 0 to w - 1 do
          set_pixel img i !j (0,0,0);
	done;
        j := !j + pasY;
      done;
      let i = ref 0 in
	while !i < w do
          for j = 1 to h - 1 do
            set_pixel img !i j (0,0,0);
          done;
          i := !i + pasX;
	done;
        let output_img_name = (img_name ^ "_G") in
          save_to_bmp img output_img_name
  end	    

(** Draws a squared grid with a specified offset **)
let draw_squared_grid img_name offset =
  draw_grid img_name offset offset  

(** Makes a list of all the intersection of the grid **)
let list_PtIntersect img pas =
  begin
    let (h,w) = (get_dims img) in
    let l = ref [] in
    let j = ref 0 in
    let i = ref 0 in
    let pt = ref (!i,!j,(get_altitude (get_pixel img !i !j)))
    in
      l := !pt::!l;
      while (!j + pas) < h do
	while (!i + pas) < w do
          i := !i + pas;
	  pt := (!i,!j,(get_altitude (get_pixel img !i !j)));
          l := !pt::!l;
	done;
	i := 0;
	j := !j + pas;
	pt := (!i,!j,(get_altitude (get_pixel img !i !j)));
	l := !pt::!l;
      done;
      (* Get all the extremity point of the image *)
      i := w;
      while (!j + pas) < h do
	pt := (!i,!j,(get_altitude (get_pixel img !i !j)));
	j := !j + pas;
	l := !pt::!l;
      done;
      j := h;
      i := 0;
      while (!i +pas) < w do
	pt := (!i,!j,(get_altitude (get_pixel img !i !j)));
	i := !i +pas;
	l := !pt::!l;
      done;
      i := w;
      pt := (!i,!j,(get_altitude (get_pixel img !i !j) ));
      l := !pt::!l;
    !l
  end
    
(** Gives the nth of a triplet **)
let triplet_to_int t n = match t with
  | (x,y,z) when n = 1 -> x
  | (x,y,z) when n = 2 -> y
  | _ -> 0

(** Draw a diagonals **)
let draw_diag img pas pt1 pt2 =
  begin
    let j = ref 0 in
    let i = ref 0 in
      while (!i < pas) do
	set_pixel img (pt1 + !i) (pt2 + !j) (0,0,0);
        i := !i + 1;
	j := !j + 1;
      done;
  end

(** Draw all diagonals **)
let draw_diags img_name pas =
  begin
    let img = load_image img_name in 
    let (h,w) = (get_dims img) in
      let listPt = list_PtIntersect img pas in
	for k = 0 to (List.length listPt) - 1 do
	  let nPt = (List.nth listPt k) in
	  let pt1 = triplet_to_int nPt 1 in
	  let pt2 = triplet_to_int nPt 2 in
            if ((pt1 + pas) < w) then
              if ((pt2 + pas) < h) then
		draw_diag img pas pt1 pt2
	done;
  end

(** Give the vertices for the triangles **)
let get_triangle imgstring pas =
  begin
    let l = [] in
    let l = ref l in
    let img = load_image imgstring in
    let (h,w) = get_dims img in
    let j = ref h in
    let i = ref w in
      while (!j > 0) do
	while (!i > 0) do
          let ptOsI = ref (!i,!j,(get_altitude (get_pixel img !i !j)))
	  in
          let ptIsI = ref (!i,(!j-pas),(get_altitude (get_pixel img !i
							(!j-pas)))
			  ) in
          let ptFsI = ref ((!i-pas),!j,(get_altitude (get_pixel img
							(!i-pas) !j))
			  ) in
          let ptOsII = ref (!i,(!j-pas),(get_altitude (get_pixel img
							 !i (!j-pas))
					)) in
          let ptIsII = ref ((!i-pas),(!j-pas),(get_altitude (get_pixel
							       img
							       (!i-pas)
							       (!j-pas))))
	  in
          let ptFsII = ref ((!i-pas),!j,(get_altitude (get_pixel img
							 (!i-pas) !j)
					)) in
            l :=
	      (!ptOsII,!ptIsII,!ptFsII)::(!ptOsI,!ptIsI,!ptFsI)::!l;
            i := !i - pas;
	done;
        i := w;
	j := !j - pas;
      done;
      !l
 end	
 
